package com.googlecode.pathmachine.nn;

/**
 *Name: NeuronLayer
 *
 *Author: John Pendlebury ported to Java from code written by Matt Buckland
 *
 *Description: Represents a group of Neurons.
 *
 *You can reuse this code provided you include these comments.
 *I'd also appreciate you letting me know via email just because I'm
 *interested.
 *
 *email: john.pendlebury2@mail.dcu.ie
 */
import java.util.*;

public class NeuronLayer {

    private List<Neuron> neurons;
    private int numInputsPerNeuron;
    private int numNeurons;

    public NeuronLayer(int numNeurons, int numInputsPerNeuron) {
        //Remember how many inouts each neuron has
        this.numInputsPerNeuron = numInputsPerNeuron;

        //Remember how many neurons we have inthis layer
        this.numNeurons = numNeurons;

        //Initailise the neurons array
        neurons = new ArrayList<Neuron>(numNeurons);

        //Create specified number of neurons with
        //specified number of inputs
        for (int i = 0; i < numNeurons; i++) {
            neurons.add(new Neuron(numInputsPerNeuron));
        }
    }

    public List<Double> processInputs(List<Double> inputs) {
        //Check that we are receiving the correct number on inputs
        assert inputs.size() == numInputsPerNeuron;

        //Create storage for outputs
        List<Double> outputs = new ArrayList<Double>(numNeurons);

        //For each neuron
        for (int j = 0; j < numNeurons; j++) {
            //Get the neurons output for the given inputs and 
            //plave it in the output List.
            outputs.add(neurons.get(j).getOutput(inputs));
        }

        return outputs;
    }

    //Here we can calulate how long the chromosome segment for thsi layer is
    //We know the number of neurons and the number of weights per neuron,
    //but we also want to encode the bias for each neuron.
    //So we add 1 to the number of weights in each neuron
    //and multiply that by the number of neurons in the layer
    public int getGeneticEncodeLength() {
        return numNeurons * (numInputsPerNeuron + 1);
    }

    public void setWeights(List<Double> layerWeights) {
        assert layerWeights.size() == getGeneticEncodeLength();

        int offset = 0;

        for (int i = 0; i < numNeurons; i++) {
            List<Double> weights = layerWeights.subList(offset, offset + numInputsPerNeuron + 1);
            offset += (numInputsPerNeuron + 1);
            neurons.get(i).setWeights(weights);
        }

    }
}
